#!/usr/bin/python
# -*- coding: utf-8 -*-

import cPickle

class LambdaAlgorithm(object):
    
    def __init__(self):
        self.packages_ = 0
        self.faults_ = 0

    def packages(self):
        return self.packages_

    def faults(self):
        return self.faults_

    def Disperse(self, state):
        return None

    def Rebuild (self, parts):
        return None

class Replication(LambdaAlgorithm):
    
    def __init__(self, size=2):
        self.size_ = size
        self.packages_ = self.size_
        self.faults_ = self.size_ - 1

    def Disperse(self, state):
        data = cPickle.dumps(state)
        return [data] * self.size_

class SingleParity(LambdaAlgorithm):

    def __init__(self, packages=3):
        self.packages_ = packages
        self.partitions_ = self.packages_ - 1
        self.faults_ = 1

    def Disperse(self, state):
        data = cPickle.dumps(state)
        dsize = len(data)
        psize = dsize / self.partitions_
        if self.partitions_ * psize != dsize:
            psize += 1
        slices = []
        # Dividing state
        for i in xrange(0, self.partitions_):
            po = i * psize
            pd = po + psize
            s = data[po:pd]
            osize = len(s)
            if osize != psize:
                s = ''.join([s, 'x' * (psize - len(s))])
            slices.append('S%04d%010d%s' % (i, osize, s))

        # Getting parity
        def strord(s):
            return [ord(i) for i in s[1:]]
        def xor(a, b):
            return a ^ b
        converted = [strord(s) for s in slices]
        parity = ['P']
        for i in xrange(0, psize + 14): # Overhead at each slice
            parity.append(chr(reduce(xor, [x[i] for x in converted])))
        slices.append(''.join(parity))
        return slices
    
